{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 分词器"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 概述\n",
    "\n",
    "分词就是将连续的字序列按照一定的规范重新组合成词序列的过程，合理的进行分词有助于语义的理解。\n",
    "\n",
    "MindSpore提供了多种用途的分词器（Tokenizer），能够帮助用户高性能地处理文本，用户可以构建自己的字典，使用适当的标记器将句子拆分为不同的标记，并通过查找操作获取字典中标记的索引。\n",
    "\n",
    "MindSpore目前提供的分词器如下表所示。此外，用户也可以根据需要实现自定义的分词器。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "| 分词器 | 分词器说明 |\n",
    "| :-- | :-- |\n",
    "| BasicTokenizer | 根据指定规则对标量文本数据进行分词。 |\n",
    "| BertTokenizer | 用于处理Bert文本数据的分词器。 |\n",
    "| JiebaTokenizer | 基于字典的中文字符串分词器。 |\n",
    "| RegexTokenizer | 根据指定正则表达式对标量文本数据进行分词。 |\n",
    "| SentencePieceTokenizer | 基于SentencePiece开源工具包进行分词。 |\n",
    "| UnicodeCharTokenizer | 将标量文本数据分词为Unicode字符。 |\n",
    "| UnicodeScriptTokenizer | 根据Unicode边界对标量文本数据进行分词。 |\n",
    "| WhitespaceTokenizer | 根据空格符对标量文本数据进行分词。 |\n",
    "| WordpieceTokenizer | 根据单词集对标量文本数据进行分词。 |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "更多分词器的详细说明，可以参见[API文档](https://www.mindspore.cn/doc/api_python/zh-CN/master/mindspore/mindspore.dataset.text.html)。\n",
    "\n",
    "> 本文档适用于CPU、GPU和Ascend环境。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## MindSpore分词器\n",
    "\n",
    "下面介绍几种常用分词器的使用方法。\n",
    "\n",
    "### BertTokenizer\n",
    "\n",
    "`BertTokenizer`是通过调用`BasicTokenizer`和`WordpieceTokenizer`来进行分词的。\n",
    "\n",
    "下面的样例首先构建了一个文本数据集和字符串列表，然后通过`BertTokenizer`对数据集进行分词，并展示了分词前后的文本结果。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "------------------------before tokenization----------------------------\n",
      "床前明月光\n",
      "疑是地上霜\n",
      "举头望明月\n",
      "低头思故乡\n",
      "I am making small mistakes during working hours\n",
      "😀嘿嘿😃哈哈😄大笑😁嘻嘻\n",
      "繁體字\n",
      "------------------------after tokenization-----------------------------\n",
      "['床' '前' '明' '月' '光']\n",
      "['疑' '是' '地' '上' '霜']\n",
      "['举' '头' '望' '明' '月']\n",
      "['低' '头' '思' '故' '乡']\n",
      "['I' 'am' 'mak' '##ing' 'small' 'mistake' '##s' 'during' 'work' '##ing'\n",
      " 'hour' '##s']\n",
      "['😀' '嘿' '嘿' '😃' '哈' '哈' '😄' '大' '笑' '😁' '嘻' '嘻']\n",
      "['繁' '體' '字']\n"
     ]
    }
   ],
   "source": [
    "import mindspore.dataset as ds\n",
    "import mindspore.dataset.text as text\n",
    "\n",
    "input_list = [\"床前明月光\", \"疑是地上霜\", \"举头望明月\", \"低头思故乡\", \"I am making small mistakes during working hours\",\n",
    "                \"😀嘿嘿😃哈哈😄大笑😁嘻嘻\", \"繁體字\"]\n",
    "dataset = ds.NumpySlicesDataset(input_list, column_names=[\"text\"], shuffle=False)\n",
    "\n",
    "print(\"------------------------before tokenization----------------------------\")\n",
    "\n",
    "for data in dataset.create_dict_iterator(output_numpy=True):\n",
    "    print(text.to_str(data['text']))\n",
    "\n",
    "vocab_list = [\n",
    "  \"床\", \"前\", \"明\", \"月\", \"光\", \"疑\", \"是\", \"地\", \"上\", \"霜\", \"举\", \"头\", \"望\", \"低\", \"思\", \"故\", \"乡\",\n",
    "  \"繁\", \"體\", \"字\", \"嘿\", \"哈\", \"大\", \"笑\", \"嘻\", \"i\", \"am\", \"mak\", \"make\", \"small\", \"mistake\",\n",
    "  \"##s\", \"during\", \"work\", \"##ing\", \"hour\", \"😀\", \"😃\", \"😄\", \"😁\", \"+\", \"/\", \"-\", \"=\", \"12\",\n",
    "  \"28\", \"40\", \"16\", \" \", \"I\", \"[CLS]\", \"[SEP]\", \"[UNK]\", \"[PAD]\", \"[MASK]\", \"[unused1]\", \"[unused10]\"]\n",
    "\n",
    "vocab = text.Vocab.from_list(vocab_list)\n",
    "tokenizer_op = text.BertTokenizer(vocab=vocab)\n",
    "dataset = dataset.map(operations=tokenizer_op)\n",
    "\n",
    "print(\"------------------------after tokenization-----------------------------\")\n",
    "\n",
    "for i in dataset.create_dict_iterator(num_epochs=1, output_numpy=True):\n",
    "    print(text.to_str(i['text']))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### JiebaTokenizer\n",
    "\n",
    "`JiebaTokenizer`是基于jieba的中文分词。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "下载字典文件`hmm_model.utf8`和`jieba.dict.utf8`，并将其放到指定位置。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "--2020-12-08 14:19:13--  https://obs.dualstack.cn-north-4.myhuaweicloud.com/mindspore-website/notebook/datasets/hmm_model.utf8\n",
      "Resolving proxy-notebook.modelarts-dev-proxy.com (proxy-notebook.modelarts-dev-proxy.com)... 192.168.0.172\n",
      "Connecting to proxy-notebook.modelarts-dev-proxy.com (proxy-notebook.modelarts-dev-proxy.com)|192.168.0.172|:8083... connected.\n",
      "Proxy request sent, awaiting response... 200 OK\n",
      "Length: 519773 (508K) [binary/octet-stream]\n",
      "Saving to: ‘hmm_model.utf8’\n",
      "\n",
      "hmm_model.utf8      100%[===================>] 507.59K  --.-KB/s    in 0.005s  \n",
      "\n",
      "2020-12-08 14:19:13 (90.6 MB/s) - ‘hmm_model.utf8’ saved [519773/519773]\n",
      "\n",
      "--2020-12-08 14:19:13--  https://obs.dualstack.cn-north-4.myhuaweicloud.com/mindspore-website/notebook/datasets/jieba.dict.utf8\n",
      "Resolving proxy-notebook.modelarts-dev-proxy.com (proxy-notebook.modelarts-dev-proxy.com)... 192.168.0.172\n",
      "Connecting to proxy-notebook.modelarts-dev-proxy.com (proxy-notebook.modelarts-dev-proxy.com)|192.168.0.172|:8083... connected.\n",
      "Proxy request sent, awaiting response... 200 OK\n",
      "Length: 5420184 (5.2M) [binary/octet-stream]\n",
      "Saving to: ‘jieba.dict.utf8’\n",
      "\n",
      "jieba.dict.utf8     100%[===================>]   5.17M  --.-KB/s    in 0.04s   \n",
      "\n",
      "2020-12-08 14:19:13 (138 MB/s) - ‘jieba.dict.utf8’ saved [5420184/5420184]\n",
      "\n"
     ]
    }
   ],
   "source": [
    "!wget -N https://obs.dualstack.cn-north-4.myhuaweicloud.com/mindspore-website/notebook/datasets/hmm_model.utf8\n",
    "!wget -N https://obs.dualstack.cn-north-4.myhuaweicloud.com/mindspore-website/notebook/datasets/jieba.dict.utf8\n",
    "!mkdir -p ./datasets/tokenizer/\n",
    "!mv hmm_model.utf8 jieba.dict.utf8 -t ./datasets/tokenizer/"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "下面的样例首先构建了一个文本数据集，然后使用HMM与MP字典文件创建`JiebaTokenizer`对象，并对数据集进行分词，最后展示了分词前后的文本结果。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "------------------------before tokenization----------------------------\n",
      "今天天气太好了我们一起去外面玩吧\n",
      "------------------------after tokenization-----------------------------\n",
      "['今天天气' '太好了' '我们' '一起' '去' '外面' '玩吧']\n"
     ]
    }
   ],
   "source": [
    "import mindspore.dataset as ds\n",
    "import mindspore.dataset.text as text\n",
    "\n",
    "input_list = [\"今天天气太好了我们一起去外面玩吧\"]\n",
    "dataset = ds.NumpySlicesDataset(input_list, column_names=[\"text\"], shuffle=False)\n",
    "\n",
    "print(\"------------------------before tokenization----------------------------\")\n",
    "\n",
    "for data in dataset.create_dict_iterator(output_numpy=True):\n",
    "    print(text.to_str(data['text']))\n",
    "\n",
    "# files from open source repository https://github.com/yanyiwu/cppjieba/tree/master/dict\n",
    "HMM_FILE = \"./datasets/tokenizer/hmm_model.utf8\"\n",
    "MP_FILE = \"./datasets/tokenizer/jieba.dict.utf8\"\n",
    "jieba_op = text.JiebaTokenizer(HMM_FILE, MP_FILE)\n",
    "dataset = dataset.map(operations=jieba_op, input_columns=[\"text\"], num_parallel_workers=1)\n",
    "\n",
    "print(\"------------------------after tokenization-----------------------------\")\n",
    "\n",
    "for i in dataset.create_dict_iterator(num_epochs=1, output_numpy=True):\n",
    "    print(text.to_str(i['text']))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### SentencePieceTokenizer\n",
    "\n",
    "`SentencePieceTokenizer`是基于[SentencePiece](https://github.com/google/sentencepiece)这个开源的自然语言处理工具包。\n",
    "\n",
    "下载文本数据集文件`botchan.txt`，并将其放置到指定位置。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "--2020-12-08 14:19:15--  https://obs.dualstack.cn-north-4.myhuaweicloud.com/mindspore-website/notebook/datasets/botchan.txt\n",
      "Resolving proxy-notebook.modelarts-dev-proxy.com (proxy-notebook.modelarts-dev-proxy.com)... 192.168.0.172\n",
      "Connecting to proxy-notebook.modelarts-dev-proxy.com (proxy-notebook.modelarts-dev-proxy.com)|192.168.0.172|:8083... connected.\n",
      "Proxy request sent, awaiting response... 200 OK\n",
      "Length: 278774 (272K) [text/plain]\n",
      "Saving to: ‘botchan.txt’\n",
      "\n",
      "botchan.txt         100%[===================>] 272.24K  --.-KB/s    in 0.003s  \n",
      "\n",
      "2020-12-08 14:19:15 (77.5 MB/s) - ‘botchan.txt’ saved [278774/278774]\n",
      "\n"
     ]
    }
   ],
   "source": [
    "!wget -N https://obs.dualstack.cn-north-4.myhuaweicloud.com/mindspore-website/notebook/datasets/botchan.txt\n",
    "!mkdir -p ./datasets/tokenizer/\n",
    "!mv botchan.txt ./datasets/tokenizer/"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "下面的样例首先构建了一个文本数据集，然后从`vocab_file`文件中构建一个`vocab`对象，再通过`SentencePieceTokenizer`对数据集进行分词，并展示了分词前后的文本结果。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "------------------------before tokenization----------------------------\n",
      "I saw a girl with a telescope.\n",
      "------------------------after tokenization-----------------------------\n",
      "['▁I' '▁sa' 'w' '▁a' '▁girl' '▁with' '▁a' '▁te' 'les' 'co' 'pe' '.']\n"
     ]
    }
   ],
   "source": [
    "import mindspore.dataset as ds\n",
    "import mindspore.dataset.text as text\n",
    "from mindspore.dataset.text import SentencePieceModel, SPieceTokenizerOutType\n",
    "\n",
    "input_list = [\"I saw a girl with a telescope.\"]\n",
    "dataset = ds.NumpySlicesDataset(input_list, column_names=[\"text\"], shuffle=False)\n",
    "\n",
    "print(\"------------------------before tokenization----------------------------\")\n",
    "\n",
    "for data in dataset.create_dict_iterator(output_numpy=True):\n",
    "    print(text.to_str(data['text']))\n",
    "\n",
    "# file from MindSpore repository https://gitee.com/mindspore/mindspore/blob/master/tests/ut/data/dataset/test_sentencepiece/botchan.txt\n",
    "vocab_file = \"./datasets/tokenizer/botchan.txt\"\n",
    "vocab = text.SentencePieceVocab.from_file([vocab_file], 5000, 0.9995, SentencePieceModel.UNIGRAM, {})\n",
    "tokenizer_op = text.SentencePieceTokenizer(vocab, out_type=SPieceTokenizerOutType.STRING)\n",
    "dataset = dataset.map(operations=tokenizer_op)\n",
    "\n",
    "print(\"------------------------after tokenization-----------------------------\")\n",
    "\n",
    "for i in dataset.create_dict_iterator(num_epochs=1, output_numpy=True):\n",
    "    print(text.to_str(i['text']))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### UnicodeCharTokenizer\n",
    "\n",
    "`UnicodeCharTokenizer`是根据Unicode字符集来分词的。\n",
    "\n",
    "下面的样例首先构建了一个文本数据集，然后通过`UnicodeCharTokenizer`对数据集进行分词，并展示了分词前后的文本结果。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "------------------------before tokenization----------------------------\n",
      "Welcome to Beijing!\n",
      "北京欢迎您！\n",
      "我喜欢English!\n",
      "------------------------after tokenization-----------------------------\n",
      "['W', 'e', 'l', 'c', 'o', 'm', 'e', ' ', 't', 'o', ' ', 'B', 'e', 'i', 'j', 'i', 'n', 'g', '!']\n",
      "['北', '京', '欢', '迎', '您', '！']\n",
      "['我', '喜', '欢', 'E', 'n', 'g', 'l', 'i', 's', 'h', '!']\n"
     ]
    }
   ],
   "source": [
    "import mindspore.dataset as ds\n",
    "import mindspore.dataset.text as text\n",
    "\n",
    "input_list = [\"Welcome to Beijing!\", \"北京欢迎您！\", \"我喜欢English!\"]\n",
    "dataset = ds.NumpySlicesDataset(input_list, column_names=[\"text\"], shuffle=False)\n",
    "\n",
    "print(\"------------------------before tokenization----------------------------\")\n",
    "\n",
    "for data in dataset.create_dict_iterator(output_numpy=True):\n",
    "    print(text.to_str(data['text']))\n",
    "\n",
    "tokenizer_op = text.UnicodeCharTokenizer()\n",
    "dataset = dataset.map(operations=tokenizer_op)\n",
    "\n",
    "print(\"------------------------after tokenization-----------------------------\")\n",
    "\n",
    "for i in dataset.create_dict_iterator(num_epochs=1, output_numpy=True):\n",
    "    print(text.to_str(i['text']).tolist())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### WhitespaceTokenizer\n",
    "\n",
    "`WhitespaceTokenizer`是根据空格来进行分词的。\n",
    "\n",
    "下面的样例首先构建了一个文本数据集，然后通过`WhitespaceTokenizer`对数据集进行分词，并展示了分词前后的文本结果。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "------------------------before tokenization----------------------------\n",
      "Welcome to Beijing!\n",
      "北京欢迎您！\n",
      "我喜欢English!\n",
      "------------------------after tokenization-----------------------------\n",
      "['Welcome', 'to', 'Beijing!']\n",
      "['北京欢迎您！']\n",
      "['我喜欢English!']\n"
     ]
    }
   ],
   "source": [
    "import mindspore.dataset as ds\n",
    "import mindspore.dataset.text as text\n",
    "\n",
    "input_list = [\"Welcome to Beijing!\", \"北京欢迎您！\", \"我喜欢English!\"]\n",
    "dataset = ds.NumpySlicesDataset(input_list, column_names=[\"text\"], shuffle=False)\n",
    "\n",
    "print(\"------------------------before tokenization----------------------------\")\n",
    "\n",
    "for data in dataset.create_dict_iterator(output_numpy=True):\n",
    "    print(text.to_str(data['text']))\n",
    "\n",
    "tokenizer_op = text.WhitespaceTokenizer()\n",
    "dataset = dataset.map(operations=tokenizer_op)\n",
    "\n",
    "print(\"------------------------after tokenization-----------------------------\")\n",
    "\n",
    "for i in dataset.create_dict_iterator(num_epochs=1, output_numpy=True):\n",
    "    print(text.to_str(i['text']).tolist())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### WordpieceTokenizer\n",
    "\n",
    "`WordpieceTokenizer`是基于单词集来进行划分的，划分依据可以是单词集中的单个单词，或者多个单词的组合形式。\n",
    "\n",
    "下面的样例首先构建了一个文本数据集，然后从单词列表中构建`vocab`对象，通过`WordpieceTokenizer`对数据集进行分词，并展示了分词前后的文本结果。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "------------------------before tokenization----------------------------\n",
      "my\n",
      "favorite\n",
      "book\n",
      "is\n",
      "love\n",
      "during\n",
      "the\n",
      "cholera\n",
      "era\n",
      "what\n",
      "我\n",
      "最\n",
      "喜\n",
      "欢\n",
      "的\n",
      "书\n",
      "是\n",
      "霍\n",
      "乱\n",
      "时\n",
      "期\n",
      "的\n",
      "爱\n",
      "情\n",
      "您\n",
      "------------------------after tokenization-----------------------------\n",
      "['my']\n",
      "['favor' '##ite']\n",
      "['book']\n",
      "['is']\n",
      "['love']\n",
      "['dur' '##ing']\n",
      "['the']\n",
      "['cholera']\n",
      "['era']\n",
      "['[UNK]']\n",
      "['我']\n",
      "['最']\n",
      "['喜']\n",
      "['欢']\n",
      "['的']\n",
      "['书']\n",
      "['是']\n",
      "['霍']\n",
      "['乱']\n",
      "['时']\n",
      "['期']\n",
      "['的']\n",
      "['爱']\n",
      "['情']\n",
      "['[UNK]']\n"
     ]
    }
   ],
   "source": [
    "import mindspore.dataset as ds\n",
    "import mindspore.dataset.text as text\n",
    "\n",
    "input_list = [\"my\", \"favorite\", \"book\", \"is\", \"love\", \"during\", \"the\", \"cholera\", \"era\", \"what\",\n",
    "    \"我\", \"最\", \"喜\", \"欢\", \"的\", \"书\", \"是\", \"霍\", \"乱\", \"时\", \"期\", \"的\", \"爱\", \"情\", \"您\"]\n",
    "vocab_english = [\"book\", \"cholera\", \"era\", \"favor\", \"##ite\", \"my\", \"is\", \"love\", \"dur\", \"##ing\", \"the\"]\n",
    "vocab_chinese = [\"我\", '最', '喜', '欢', '的', '书', '是', '霍', '乱', '时', '期', '爱', '情']\n",
    "\n",
    "dataset = ds.NumpySlicesDataset(input_list, column_names=[\"text\"], shuffle=False)\n",
    "\n",
    "print(\"------------------------before tokenization----------------------------\")\n",
    "\n",
    "for data in dataset.create_dict_iterator(output_numpy=True):\n",
    "    print(text.to_str(data['text']))\n",
    "\n",
    "vocab = text.Vocab.from_list(vocab_english+vocab_chinese)\n",
    "tokenizer_op = text.WordpieceTokenizer(vocab=vocab)\n",
    "dataset = dataset.map(operations=tokenizer_op)\n",
    "\n",
    "print(\"------------------------after tokenization-----------------------------\")\n",
    "\n",
    "for i in dataset.create_dict_iterator(num_epochs=1, output_numpy=True):\n",
    "    print(text.to_str(i['text']))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "MindSpore-1.0.1",
   "language": "python",
   "name": "mindspore-1.0.1"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
